#include <QMessageBox>
#include "molsurfaceplugin.h"
#include "../../mainwindow.h"
#include "../../datamanager/datamanager.h"
#include "../../renderer/rendermanager.h"
#include "../../datamanager/proteindatanode.h"
#include "../../datamanager/geometrydatanode.h"
#include "../../datamanager/reg3volumedatanode.h"
#include "molsurfacecontrol.h"
#include "../../contour/molskin.h"
#include "../../contour/mcconextractor.h"
#include "../../contour/blurmap.h"

using namespace PBVP;
MolSurfacePlugin::MolSurfacePlugin()
{
	m_pControl = new MolSurfaceControl(this);
}

MolSurfacePlugin::~MolSurfacePlugin()
{
	delete m_pControl;
	delete progressBar;
}

void MolSurfacePlugin::initialize(MainInterface* mainInterface)
{
	Plugin::initialize(mainInterface);
	m_pDataManager = m_pMainInterface->getDataManager();
	m_pRenderManager = m_pMainInterface->getRenderManager();

	molSurfAction = new QAction(tr("Construct Molecular Surface"), m_pMainInterface->getMainWindow());
	molSurfAction->setStatusTip(description());
	connect(molSurfAction, SIGNAL(triggered()), this, SLOT(constructSurface()));

	progressBar = new QProgressBar();
	progressBar->setWindowTitle("Computing Mol Surface");
	progressBar->move(400, 400);
	progressBar->hide();
	progressBar->setMinimum(0);
	progressBar->setMaximum(100);
}

bool MolSurfacePlugin::isSupported(DataNode* pNode)
{
#ifdef __GNU__
	if(pNode->data()->getDataSetType() == PROTEIN_DATA) return true;
#else
	ProteinDataNode *pProteinNode = dynamic_cast<ProteinDataNode *>(pNode);
	if (pProteinNode)
	{
		return true;
	}
#endif
	return false;
}

//////////////////////////////////////////////////////////////////////////
// public slots
//////////////////////////////////////////////////////////////////////////
void MolSurfacePlugin::constructSurface()
{
	DataNode *pNode = m_pDataManager->getCurrentNode();
	if (!pNode)
	{
		QMessageBox::critical(m_pMainInterface->getMainWindow(), "Error", "No Data Selected in DataManager");
		return;
	}
	if(!isSupported(pNode)) {
		QMessageBox::critical(m_pMainInterface->getMainWindow(), "Error", "Only Protein Data can be used to construct volume");
		return;
	}
#ifdef __GNU__
	ProteinDataNode *pProteinNode = (ProteinDataNode *)(pNode);
#else
	ProteinDataNode *pProteinNode = dynamic_cast<ProteinDataNode *>(pNode);
#endif
	m_pControl->initialize(pProteinNode);

	if (m_pControl->exec())
	{
		ProteinData *pProtein = (ProteinData *)(pProteinNode->data());
		QVector<Atom> atoms;
		if(m_pControl->getSurfMode() == MOL_PROTEIN) {
			atoms = pProtein->getAtoms();
		} else if (m_pControl->getSurfMode() == MOL_CHAIN)
		{
			int cid = m_pControl->getChainId();
			atoms = pProtein->getChain(cid)->getAtoms();
		} else { // ligand
			int lid = m_pControl->getLigandId();
			atoms = pProtein->getLigand(lid)->getAtoms();
		}
		// printf("molecular surface plugin\n");

		progressBar->setValue(0);
		progressBar->show(); 
		//BlurMap *pBlurmap = new BlurMap();
		
		//Reg3DVolumeData *pReg3Data = pBlurmap->constructVolume(atoms);
		//MCContourExtractor *conExtractor = new MCContourExtractor();
		//GeometryData *pSurf = conExtractor->extractContour(pReg3Data, 1.0);
		//delete pReg3Data;
		//delete conExtractor;
		//delete pBlurmap;
		GeometryData *pSurf;
		if(m_pControl->getSurfMode() == MOL_LIGAND) {
			BlurMap *pBlurMap = new BlurMap();
			//AxisAlignedBox bbox = pNode->boundingBox();
			//pBlurMap->setMinMaxExt(bbox.getMinimum(), bbox.getMaximum());
			pSurf = pBlurMap->constructSurface(atoms);
			delete pBlurMap;
		} else {
			MolSkin *pMolSkin = new MolSkin();
			pMolSkin->setProgressBar(progressBar);
			pSurf = pMolSkin->constructMolSurface(atoms);
			delete pMolSkin;
			/*BlurMap *pBlurMap = new BlurMap();
			pSurf = pBlurMap->constructSurface(atoms);
			delete pBlurMap;*/
		}
		progressBar->hide();

		GeometryDataNode *pGeoNode = new GeometryDataNode(pSurf, m_pMainInterface);
		pGeoNode->setName(pNode->getName().append("_surface"));
		//m_pRenderManager->setDefaultRenderer(pGeoNode);
		m_pDataManager->addDataNode(pGeoNode);
	}
}
Q_EXPORT_PLUGIN2(molsurface, MolSurfacePlugin)


